<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\config\reader;

interface IConcrete
{
  /**
   * Constructur
   * used by factory
   * @see getData
   * !!! implement getData($sUri) in child class
   *
   * @param $sUri URI of config location
   */
  public function __construct($sUri);

  /**
   * Implement this in child class.
   * this function should read ini data from uri and save it to $this->aData Cache
   *
   * @param $sUri URI of config location
   */
  public function getData($sUri);

  /**
   * Returns domain array (@see getDomain) if $key not set (default NULL)
   * or returns key (@see getKey) if domain and key are set
   *
   * @param $sDomain  Domain
   * @param $key      Key
   * @return  mixed|array
   */
  public function get($sDomain, $key = \NULL);

  /**
   * Returns value of $key in $sDomain
   * Converts value to correct type according to key prefix
   *
   * @param $sDomain  Domain
   * @param $key      Key
   * @return mixed
   */
  public function getKey($sDomain, $key);

  /**
   * Returns array with keys/values in $sDomain
   * Converts values to correct type according to key prefixes
   *
   * @param string  Domain
   * @return  array
   */
  public function getDomain($sDomain);

  /**
   * To return a default value (key is not found), use this chaining call,
   * as example \FALSE as default value:
   * $oReader->setDefault(\FALSE)->get($domain, $key);
   * will be deleted after next get / getkey use
   *
   * @chainable
   * @param $value default value
   * @return \crcl\base\config\reader\IConcrete
   */
  public function setDefault($value);

  /**
   * To return all string values as lowercase, use this chaining call,
   * as example
   * $oReader->setLowercase()->get($domain, $key);
   *
   * @chainable
   * @param $bLowerCase activate lowercase mode, defaults to \TRUE
   * @return \crcl\base\config\reader\IConcrete
   */

//  public function setLowercase($bLowercase = \TRUE);
}

abstract class Base implements IConcrete
{
  public function __construct($sUri)
  {
    $this->sUri = $sUri;
    $this->getData($sUri);
  }

  //@codeCoverageIgnoreStart
  public function getData($sUri)
  {
    throw new Exception(
      'getData not yet implemented',
      Exception::ERROR_BASE_GETDATANOTIMPLEMENTED, array('sUri' => $sUri));
  }
  //@codeCoverageIgnoreEnd

  public function get($sDomain, $key = \NULL)
  {
    if (\is_null($key))
    {
      return $this->getDomain($sDomain);
    }
    else
    {
      return $this->getKey($sDomain, $key);
    }
  }

  public function getKey($sDomain, $key)
  {
    if (isset($this->aData[$sDomain][$key]))
    {
      $value = $this->aData[$sDomain][$key];
//      $sValue = $this->_encodeValue($key, $sValue);
//      if ($bLowerCase)
//      {
//          $sValue = \strtolower($sValue);
//      }
        return $value;
    }
    //when we are here, key doesnt exists.
    //default?
    if ($this->default !== self::NODEFAULT)
    {
      $return = $this->default;
      $this->default = self::NODEFAULT;
      return $return;
    }
    //no key, no default, so sad
    throw new Exception(
      'Key does not exist',
      Exception::ERROR_BASE_KEYNOTEXIST,
      array(
        'uri' => $this->sUri,
        'domain' => $sDomain,
        'key' => $key,
        'lowercase' => \FALSE)); //todo
  }

  public function setDefault($value)
  {
    $this->default = $value;
    return $this;
  }

  public function getDomain($sDomain)
  {
    //todo what about default?
    if (isset($this->aData[$sDomain]))
    {
//      $aDomain = $this->_encodeDomain($this->_aData[$sDomain]);
      return $this->aData[$sDomain];
    }
    throw new Exception(
      'Domain does not exist',
      Exception::ERROR_BASE_DOMAINNOTEXIST,
      array(
        'uri' => $this->sUri,
        'domain' => $sDomain,
        'default' => '',
        'lowercase' => \FALSE)); //todo
  }

 // public function setLowercase($bLowercase = \TRUE)
 // {

 // }

  /** PROTECTED ***********************************************************************************/

  protected $aData = array();
  protected $sUri = \NULL;

  /** PRIVATE *************************************************************************************/

  //should not occur as normal default value ;-)
  const NODEFAULT = '--xx--no--default--';

  private $default = self::NODEFAULT;

/*
  private function _encodeValue($key, $value)
  {
    if (\is_array($value))
    {
      foreach ($value as $sInnerKey => $innerValue)
      {
        $value[$sInnerKey] = $this->_encodeValue($sInnerKey, $innerValue);
      }
      return $value;
    }

    $value = \htmlspecialchars_decode($value);
    $value = \base\Application::replace($value);
    $value = \base\System::replaceVars($value);
    $value = \base\Tier::replace($value);
    $value = \base\system\Prefix::convertValueByKey($value, $key);
    return $value;
  }

  private function _encodeDomain($aDomain)
  {
    foreach ($aDomain as $sKey => $value)
    {
      $value = $this->_encodeValue($sKey, $value);
      $aDomain[$sKey] = $value;
    }
    return $aDomain;
  }
 */
}